﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using NAudio.Wave;
using System.Diagnostics;
namespace WindowsFormsApplication3
{
    /// <summary>
    /// Control for viewing waveforms
    /// </summary>
    public class ScrollWaveView : NAudio.Gui.WaveViewer
    {
        /// <summary> 
        /// Required designer variable.
        /// </summary>
        
        private int grabPosition = 0;
        private int grabWidth = 100000;
        public delegate void WaveScrollHandler(object sender, WaveScrollEventArgs e);
        public event WaveScrollHandler OnWaveScrolled;

        public class WaveScrollEventArgs : EventArgs
        {
            public int SamplePosition { get; private set; }
            //private ArrangeStartingPosition;
            public WaveScrollEventArgs(int pos)
            {
                SamplePosition = pos;
            }
        } 
        public int GrabPosition
        {
            get
            {
                return grabPosition;
            }
            set
            {
                grabPosition = value; 
            }
        }
        /// <summary>
        /// Creates a new WaveViewer control
        /// </summary>
        public ScrollWaveView()
        {
            // This call is required by the Windows.Forms Form Designer.
            InitializeComponent();
            this.DoubleBuffered = true;

        }

        /// <summary>
        /// <see cref="Control.OnPaint"/>
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                if (waveStream == null)
                    return;
                int grabPosPixcel = grabPosition / samplesPerPixel;
                int grabWidthPixcel = grabWidth / samplesPerPixel;
                //Debug.WriteLine("on paint grabWidthPixcel" + grabWidthPixcel);
                Color grabColor = hoverGrab ? Color.Red : Color.Blue;
                if (isDragging)
                    grabColor = Color.White;
                try
                {
                    e.Graphics.FillRectangle(new SolidBrush(grabColor), new Rectangle((int)grabPosPixcel, 0, (int)grabWidthPixcel, this.Width));
                }
                catch (Exception exp)
                {
                    Debug.WriteLine(exp.Message);
                }
                if (waveStream != null)
                {
                    waveStream.Position = 0;
                    int bytesRead;
                    byte[] waveData = new byte[samplesPerPixel * bytesPerSample];
                    waveStream.Position = startPosition + (e.ClipRectangle.Left * bytesPerSample * samplesPerPixel);

                    for (float x = e.ClipRectangle.X; x < e.ClipRectangle.Right; x += 1)
                    {
                        short low = 0;
                        short high = 0;
                        bytesRead = waveStream.Read(waveData, 0, samplesPerPixel * bytesPerSample);
                        if (bytesRead == 0)
                            break;
                        for (int n = 0; n < bytesRead; n += 2)
                        {
                            short sample = BitConverter.ToInt16(waveData, n);
                            if (sample < low) low = sample;
                            if (sample > high) high = sample;
                        }
                        float lowPercent = ((((float)low) - short.MinValue) / ushort.MaxValue);
                        float highPercent = ((((float)high) - short.MinValue) / ushort.MaxValue);
                        e.Graphics.DrawLine(Pens.Black, x, this.Height * lowPercent, x, this.Height * highPercent);
                    }
                }

                base.OnPaint(e);
            }
            catch(Exception exc)
            {
                Debug.WriteLine(exc.Message);
            }
        }


        #region Component Designer generated code
        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // ScrollWaveView
            // 
            this.Name = "ScrollWaveView";
            this.Load += new System.EventHandler(this.ScrollWaveView_Load);
            this.ResumeLayout(false);

        }
        #endregion

        private void CustomWaveView_Load(object sender, EventArgs e)
        {

        }
        private bool isMouseDown = false;
        private Point mouseStartPos;
        int offset_on_grab = 0;
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (waveStream == null || waveStream.Length == 0)
                return;
            isMouseDown = true;
            this.Capture = true;
            mouseStartPos = e.Location;
            int grabPosPixcel = grabPosition / samplesPerPixel;
            int grabWidthPixcel = grabWidth / samplesPerPixel; 
            if (e.X >= grabPosPixcel && e.X < grabPosPixcel + grabWidthPixcel)
            {
                offset_on_grab = e.X - grabPosPixcel;
            }
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (waveStream == null || waveStream.Length == 0)
                return;
            isMouseDown = false;
            Capture = false;
            isDragging = false;
        }
        private bool hoverGrab = false;
        private bool isDragging = false;
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (waveStream == null || waveStream.Length == 0)
                return;
            try
            {
                base.OnMouseMove(e);
                int grabPosPixcel = grabPosition / samplesPerPixel;
                int grabWidthPixcel = grabWidth / samplesPerPixel;

                if (!isMouseDown)
                {
                    if (e.X >= grabPosPixcel && e.X < grabPosPixcel + grabWidthPixcel)
                    {
                        hoverGrab = true;
                        //Debug.WriteLine(" in grab");

                    }
                    else
                    {
                        hoverGrab = false;
                        //Debug.WriteLine(" out grab");

                    }
                    InvalidateGrab();

                }
                else
                {
                    InvalidateGrab();

                    hoverGrab = true;
                    int X = Math.Min(Math.Max(offset_on_grab, e.X), (int)this.Width - grabWidthPixcel + offset_on_grab);
                    //int validateMouseX = Math.Min(Math.Max(offset_on_grab, e.X), (int)this.Width - grabWidthPixcel+ offset_on_grab);
                    grabPosPixcel = X - offset_on_grab;
                    grabPosition = grabPosPixcel * samplesPerPixel;
                    Debug.WriteLine("##################");
                    Debug.WriteLine("grabPosition" + grabPosition);
                    Debug.WriteLine("grabPosPixcel" + grabPosPixcel);
                    Debug.WriteLine("samplesPerPixel" + samplesPerPixel);
                    Debug.WriteLine("width pixcel" + this.ClientRectangle.Width);
                    Debug.WriteLine("##################");
                    int sample_tmp = this.ClientRectangle.Width * SamplesPerPixcel;
                    //Debug.Assert(Samples == sample_tmp);

                    isDragging = true;
                    try { 
                        WaveScrollEventArgs args = new WaveScrollEventArgs(grabPosition);
                        OnWaveScrolled(this, args);
                    }
                    catch(Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                    }

                    InvalidateGrab();
                }
            }
            catch (Exception)
            {

            }
            //Invalidate();
        }
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (waveStream == null || waveStream.Length == 0)
                return;
            hoverGrab = false;

            InvalidateGrab();

        }

        private void InvalidateGrab()
        {
            int grabPosPixcel = grabPosition / samplesPerPixel;
            int grabWidthPixcel = grabWidth / samplesPerPixel;

            Invalidate(new Rectangle(grabPosPixcel, 0, grabPosPixcel + grabWidthPixcel, this.ClientRectangle.Bottom));
        }
        private void ScrollWaveView_Load(object sender, EventArgs e)
        {

        }
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            if(waveStream != null && waveStream.Length > 0)
            {

                SamplesPerPixcel = this.Samples / this.ClientRectangle.Width;
                Invalidate();
            }
        }

    }
}
